#include "dirOpt.h"

//在得到netfd与用户名后，进行循环实际操作前，初始化一下
int init_session(ClientSession *session,MYSQL *mysql,char *user_name,int netfd) {

    // 安全初始化结构体
    memset(session, 0, sizeof(ClientSession));

    /* // 处理根目录,这里可能要创建基于客户名的单独文件夹，先暂时这样写，到时候可以在安全根目录上再mkdir */
    /* if (!root){ */
    /*     root = NET_SAVE_ROOT; */
    /* } */

    /* // 直接复制根目录 */
    /* strncpy(session->root_dir, root, sizeof(session->root_dir)); */

    /* // 确保以'/'结尾 */
    /* size_t len = strlen(session->root_dir); */
    /* if (len > 0 && session->root_dir[len-1] != '/') { */
    /*     if (len < MAX_PATH_LEN - 1) { */
    /*         strncat(session->root_dir, "/", 2); */
    /*     } */
    /* } */

    // 设置当前目录
    strncpy(session->current_dir,"/",2);
    session->netfd = netfd;
    strncpy(session->user_name,user_name,strlen(user_name)+1);
    session->pcn = NULL; //初始化为'/'?、id只是附带加上去、判断top为1？
    session->stack_top = 0;
    PathComponent * pcn_tmp = (PathComponent *)calloc(1,sizeof(PathComponent));
    strncpy(pcn_tmp->name,"/",2);
    pcn_tmp->next = session->pcn;
    session->stack_top ++;
    session->pcn = pcn_tmp;

    session->mysql = mysql;
    //查询该用户根路径id并赋值
    char sql[5000] = {0};
    sprintf(sql,"select id from %s where user_name = '%s'"\
            "and  path = '/' and is_delete = 0;",TABLE_NAME,session->user_name);
    mysql_store_result(mysql);
    int qret = mysql_query(mysql,sql);
    if(qret != 0){
        printf("InitCss-Error: %s\n", mysql_error(mysql));
        /* send(session->netfd,"!server error...",17,0); */
        return -1;
    }
    MYSQL_RES *result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    int path_id = atoi(row[0]);
    session->pcn_id = path_id;
    session->pcn->path_id = path_id;
    session->root_id = path_id;

    /* /1* session->stack_top = 0; *1/ */
    /* session->netfd = netfd; */
    /* session->opt = 0; */

    /* session->mysql = mysql; */
    /* /1* memset(session->user_name,0,sizeof(session->user_name)); *1/ */
    /* strncpy(session->user_name,user_name,strlen(user_name)+1); */
    /* memset(session->current_dir_tmp,0,sizeof(session->current_dir_tmp)); */

    return 0;
}


int handle_path(ClientSession* css){

    //暂只处理cd 单字符命令进家目录
    if((strcmp(&css->recv_path[0]," ") == 0 ||strcmp(&css->recv_path[0],"~") == 0 || strcmp(&css->recv_path[0],"/")== 0) 
       && strlen(css->recv_path)==1) {
        //可做资源清理
        css->pcn = NULL;
        
        PathComponent * pcn_tmp = (PathComponent *)calloc(1,sizeof(PathComponent));
        strncpy(pcn_tmp->name,"/",2);
        pcn_tmp->path_id = css->root_id;
        pcn_tmp->next = css->pcn;
        css->pcn_id = css->root_id;
        css->stack_top = 1;
        css->pcn = pcn_tmp;
        bzero(css->current_dir,sizeof(css->current_dir));

        strncpy(css->current_dir,"/",2);
        return 0;
    }

    // 分割路径组件
    char *saveptr;
    char *token = strtok_r(css->recv_path, "/", &saveptr);

    while (token != NULL) {

        if (strcmp(token, ".") == 0) {
            // 忽略当前目录
        }
        else if (strcmp(token, "..") == 0) {
            // 回退上级目录
            if(css->stack_top == 1){
                token = strtok_r(NULL, "/", &saveptr);
                continue;
            }
            else{
                css->pcn = css->pcn->next;
                css->stack_top --;
                css->pcn_id = css->pcn->path_id;
            }
        }
        else {
            // 添加新组件
            PathComponent * pcn_tmp = (PathComponent *)calloc(1,sizeof(PathComponent));
            strncpy(pcn_tmp->name,token,sizeof(pcn_tmp->name));

            char sql[5000] = {0};
            sprintf(sql,"select id from %s where user_name = \"%s\""\
                    "and file_name = \"%s\";",TABLE_NAME,css->user_name,token);
            mysql_store_result(css->mysql);
            int qret = mysql_query(css->mysql,sql);
            if(qret != 0){
                printf("handle_path-ADD-Error: %s\n", mysql_error(css->mysql));
                /* send(css->netfd,"!server Error...",17,0); */
                return -1;
            }
            MYSQL_RES *result = mysql_store_result(css->mysql);
            if(mysql_num_rows(result) == 0){
                pcn_tmp->path_id = -2;

            }else{
                MYSQL_ROW row = mysql_fetch_row(result);
                pcn_tmp->path_id = atoi(row[0]);
            }
            /* MYSQL_ROW row = mysql_fetch_row(result); */
            /* int path_id = atoi(row[0]); */
            /* pcn_tmp->path_id = path_id; */

            pcn_tmp->next = css->pcn;
            css->stack_top ++;
            css->pcn = pcn_tmp;
            css->pcn_id = css->pcn->path_id;
            printf("tcon:%s\n",css->pcn->name);

        }
        token = strtok_r(NULL, "/", &saveptr);
    }

    if(css->stack_top == 1){
        bzero(css->current_dir,sizeof(css->current_dir));
        strncpy(css->current_dir,"/",2);
    }
    printf("tcon_:%s\n",css->pcn->name);

    return 0;
}

//弹已经优化好的栈组成路径
int build_path(ClientSession *css){

    PathComponent *pcn = css->pcn;
    char buf[MAX_PATH_LEN] = {0};

    while(pcn->next){
        if(strcmp(&css->current_dir[0],"/")==0){
            css->current_dir[0] = '\0';
        }

        char buf_tmp[MAX_PATH_LEN+64] = {0};
        sprintf(buf_tmp,"%s/%s",pcn->name,buf);
        strncpy(buf,buf_tmp,sizeof(buf));
        pcn = pcn->next;
        printf("rep?\n");
    }
    printf("b_p:%s\n",buf);

    memset(css->current_dir,0,sizeof(css->current_dir));
    strncpy(css->current_dir,"/",2);
    strncat(css->current_dir,buf,sizeof(css->current_dir));
    printf("bp_:%s\n",css->current_dir);

    return 0;
}

/* int sum_path(ClientSession *css){ */

/*     char bufs[MAX_PATH_LEN]; */
/*     char bufc[MAX_PATH_LEN]; */
/*     strncpy(bufs,css->root_dir,sizeof(bufs)); */
/*     strncpy(bufc,css->current_dir,sizeof(bufs)); */

/*     if(bufs[strlen(bufs)-1] == '/'&&bufc[0] == '/'){ */
/*         bufs[strlen(bufs)-1] = '\0'; */
/*     } */

/*     bzero(css->sumPath,sizeof(css->sumPath)); */
/*     strncat(css->sumPath,bufs,sizeof(css->sumPath)); */
/*     strncat(css->sumPath,bufc,sizeof(css->sumPath)); */

/*     return 0; */
/* } */


//辅助函数，验证绝对路径的真实性，存在的话会返回1
int is_path_accessible(ClientSession *css){


    //可先做绝对查询了


    handle_path(css);
    build_path(css);
    /* sum_path(css); */

    /* // 检查路径是否存在 */
    /* if (access(css->sumPath, F_OK) != 0){ */
    /*     printf("the path no exist\n"); */
    /*     return false; */
    /* } */
    // 移除结尾的斜杠（mkdir需要）
    size_t len = strlen(css->current_dir);
    if (len > 1 && css->current_dir[len-1] == '/') {
        css->current_dir[len-1] = '\0';
    }

    char sql[5000] = {0};
    sprintf(sql,"select * from %s where user_name = '%s' "\
            "and path = '%s' and type = 'd';",TABLE_NAME,css->user_name,css->current_dir);
    printf("_unav_sql_:%s\n",sql);
    mysql_store_result(css->mysql);
    int qret = mysql_query(css->mysql,sql);
    if(qret != 0){
        printf("isPthAce-Error: %s\n", mysql_error(css->mysql));
        return false;
    }
    MYSQL_RES *result = mysql_store_result(css->mysql);
    if(mysql_num_rows(result) == 0){
        return 0;
    }



    /* // 检查访问权限 */
    /* if (access(css->sumPath, R_OK | X_OK) != 0){ */
    /*     printf("the path cant access\n"); */
    /*     return false; */
    /* } */

    /* // 如果是目录路径，确保是目录 */
    /* struct stat path_stat; */
    /* if (stat(css->sumPath, &path_stat)){ */
    /*     printf("the path no dir\n"); */
    /*     return false; */
    /* } */



    //数据库查询存在





    return 1;
}


int check_dir(ClientSession *css){

    char savecur[MAX_PATH_LEN] = {0};

    strncpy(savecur,css->current_dir,strlen(css->current_dir)+1);
    printf("_ckdir:%s\n",css->current_dir);

    if(!is_path_accessible(css)){
        
        bzero(css->recv_path,sizeof(css->recv_path));
        strncpy(css->recv_path,savecur,strlen(savecur)+1);
        bzero(css->current_dir,sizeof(css->current_dir));
        strncpy(css->current_dir,"/",2);
        css->pcn_id = css->root_id;
        css->stack_top = 0;

        css->pcn = NULL;
        PathComponent * pcn_tmp = (PathComponent *)calloc(1,sizeof(PathComponent));
        strncpy(pcn_tmp->name,"/",2);
        pcn_tmp->next = css->pcn;
        pcn_tmp->path_id = css->root_id;
        css->stack_top ++;
        css->pcn = pcn_tmp;

        handle_path(css);
        build_path(css);
        /* sum_path(css); */
        css->opt = 0;
        /* send(css->netfd,"path nonavail",14,0); */
        return -1;
    }

    if(css->opt == 1){
        bzero(css->recv_path,sizeof(css->recv_path));
        strncpy(css->recv_path,savecur,strlen(savecur)+1);
        bzero(css->current_dir_tmp,sizeof(css->current_dir_tmp));
        strncpy(css->current_dir_tmp,css->current_dir,strlen(css->current_dir)+1);
        css->current_dir_tmp_id = css->pcn->path_id;

        css->stack_top = 0;
        css->pcn = NULL;
        PathComponent * pcn_tmpc2 = (PathComponent *)calloc(1,sizeof(PathComponent));
        strncpy(pcn_tmpc2->name,"/",2);
        pcn_tmpc2->next = css->pcn;
        pcn_tmpc2->path_id = css->root_id;
        css->pcn = pcn_tmpc2;
        css->stack_top ++;
        css->pcn_id = css->root_id;

        /* char savesum[MAX_PATH_LEN] = {0}; */
        /* strncpy(savesum,css->sumPath,strlen(css->sumPath)+1); */
        /* char dir_tmp[MAX_PATH_LEN] = {0}; */
        /* strncpy(dir_tmp,css->current_dir,strlen(css->current_dir_tmp)+1); */
        
        bzero(css->current_dir,sizeof(css->current_dir));
        strncpy(css->current_dir,"/",2);
        printf("ck_rvdir:%s\n",css->recv_path);
        handle_path(css);
        build_path(css);

        /* strncpy(css->sumPath,savesum,strlen(savesum)+1); */                                     
        css->opt = 0;
        printf("ckdir_:%s\n",css->current_dir);

    }

    printf("check_dir success\n");

    return 0;

}

int cd_dir(ClientSession * css){

    if(check_dir(css) == -1){ 
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    char buf[MAX_PATH_LEN] = {0};

    if(strlen(css->current_dir)>1&&css->current_dir[strlen(css->current_dir)-1] == '/'){
        strncpy(buf,css->current_dir,strlen(css->current_dir)-1);
    }else if(strlen(css->current_dir)>1){
        strncpy(buf,css->current_dir,strlen(css->current_dir)+1);
    }
    if(strlen(css->current_dir)<=1) buf[0] = '/';


    //应该不用再联系数据库了，更新一下可能存在的id？

    printf("cd success:%s\n",buf);
    send(css->netfd,buf,strlen(buf),0);

    return 0;
}

int ls_dir(ClientSession *css){

    css->opt = 1;
    if(check_dir(css) == -1){
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    /* DIR *dir = opendir(css->sumPath); */

    /* if (!dir) { */
    /*     fprintf(stderr, "Cannot open directory: %s\n", css->sumPath); */
    /*     return -1; */
    /* } */



    char dirList[MAX_LS_BUFFER] = {0};

    char sql[5000] = {0};
    sprintf(sql,"select file_name,type from %s where parent_id  = '%d' and is_delete = 0;",
            TABLE_NAME,css->current_dir_tmp_id);
    printf("ls_sql:%s\n",sql);
    mysql_store_result(css->mysql);
    int qret = mysql_query(css->mysql,sql);
    if(qret != 0){
        printf("ls-Error: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }
    /* MYSQL_RES *result = mysql_store_result(css->mysql); */
    /* MYSQL_ROW row = mysql_fetch_row(result); */
    /* int path_id = atoi(row[0]); */


    MYSQL_RES *rows =mysql_store_result(css->mysql);
    printf("col num =%u,row num = %lu\n",mysql_num_fields(rows),mysql_num_rows(rows));
    for(unsigned long i=0;i<mysql_num_rows(rows);++i)
    {
        MYSQL_ROW row = mysql_fetch_row(rows);//取出下一行
        if(!strcmp(row[1],"d")){
            strncat(dirList,row[0],strlen(row[0])+1);
            strncat(dirList,"/",2);
            strncat(dirList,"\t",2); 
            continue;
        }        
        strncat(dirList,row[0],strlen(row[0])+1);
        strncat(dirList,"\t",2);
        /* for(unsigned int j=0;j<mysql_num_fields(rows);++j) */
        /* { */
        /*     printf("%s\t",row[j]); */
        /* } */
            /* printf("\n"); */
    }






    /* struct dirent *entry; */

    /* while ((entry = readdir(dir)) != NULL) { */
    /*     char buf[512] = {0}; */

    /*     // 跳过隐藏文件 */
    /*     if (entry->d_name[0] == '.') continue; */

    /*     // 获取文件类型标记 */
    /*     char type = ' '; */

    /*     if (entry->d_type == DT_DIR) { */
    /*         type = '/'; */
    /*     } else if (entry->d_type == DT_LNK) { */
    /*         type = '@'; */
    /*     } else if (entry->d_type == DT_FIFO) { */
    /*         type = '|'; */
    /*     } else if (entry->d_type == DT_SOCK) { */
    /*         type = '='; */
    /*     } */

    /*     sprintf(buf,"%s%c\t",entry->d_name,type); */
    /*     strcat(dirList,buf); */
    /* } */

    /* closedir(dir); */
    printf("(DirOpt)ls success:%s\n",dirList);
    send(css->netfd,dirList,strlen(dirList)+1,0);

    return 0;
}


int pwd_dir(ClientSession *css){

    char pwdBuf[MAX_PATH_LEN] = {0};

    //笨方法，确保即将输出的pwd内容以'/'开头,并无'/'结尾                                            
    if(css->current_dir[0] != '/'){
        pwdBuf[0] = '/';
        strncat(pwdBuf,css->current_dir,sizeof(pwdBuf)-1);
    }
    else{
        strncpy(pwdBuf,css->current_dir,sizeof(pwdBuf));
    }
    if(pwdBuf[strlen(pwdBuf)-1] == '/'&&strlen(pwdBuf)>1) pwdBuf[strlen(pwdBuf)-1] = '\0';

    printf("pwd_dir success: %s\n",pwdBuf);
    send(css->netfd,pwdBuf,strlen(pwdBuf)+1,0);

    return 0;
}

int mk_dir(ClientSession *css){

    char recvTmp[MAX_PATH_LEN] = {0};
    strncpy(recvTmp,css->recv_path,sizeof(recvTmp));
    char *last_slash = strrchr(css->recv_path, '/'); // 查找最后一个'/'的位置

    char lastname[1024] = {0};
    if (last_slash != NULL) {
        strncpy(lastname,last_slash+1,strlen(last_slash+1));
        *last_slash = '\0'; // 截断字符串（保留最后一个'/'之前的内容）
    }else{
        if(strlen(css->recv_path)>=1){
            bzero(css->recv_path,sizeof(css->recv_path));
            strncpy(lastname,recvTmp,strlen(recvTmp)+1);
        }
    }

    css->opt = 1;
    if(check_dir(css) == -1) 
    {
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    char target[MAX_PATH_LEN] = {0};

    /* strncat(target,css->sumPath,strlen(css->sumPath)+1); */
    strncat(target,css->current_dir,strlen(css->current_dir)+1); //↑替换
    strncat(target,lastname,strlen(lastname)+1);


    // 移除结尾的斜杠（mkdir需要）
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }

    /* // 检查目录是否已存在 */
    /* if (access(target, F_OK) == 0) { */
    /*     fprintf(stderr, "Directory already exists: %s\n", target); */
    /*     return false; */
    /* } */
    char sql[5000] = {0};
    sprintf(sql,"select * from %s where user_name = '%s' and path = '%s' and is_delete = 0 and type = 'd';",
            TABLE_NAME,css->user_name,target);
    printf("mksql:%s\n",sql);
    mysql_store_result(css->mysql);
    int qret = mysql_query(css->mysql,sql);
    if(qret != 0){
        printf("mkdir-Error1: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }                                                                                                                
    MYSQL_RES *rows =mysql_store_result(css->mysql);

    if(mysql_num_rows(rows)){
        printf("the dir already exist\n");
        send(css->netfd,"the dir already exist",22,0);
        return -1;
    }

    /* // 创建目录（权限：用户读写执行） */
    /* if (mkdir(target, 0700)) { */                                                       
    /*     perror("mkdir failed"); */
    /*     return false; */
    /* } */
    char sql2[6000] = {0};
    sprintf(sql2,"insert %s (file_name,user_name,parent_id,type,path,is_delete,hashval)"\
            "values ('%s','%s','%d','d','%s',0,NULL);",
            TABLE_NAME,lastname,css->user_name,css->current_dir_tmp_id,target);
    printf("mksql2:%s\n",sql2);
    mysql_store_result(css->mysql);
    int qret2 = mysql_query(css->mysql,sql2);
    if(qret2 != 0){
        printf("mkdir-Error2: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    printf("make success\n");
    send(css->netfd,"mksuccess",9,0);

    return 0;
}

int rm_dir(ClientSession * css){

    css->opt = 1;
    if(check_dir(css) == -1){
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    char target[MAX_PATH_LEN] = {0};
    /* strncpy(target,css->sumPath,sizeof(target)); */
    strncpy(target,css->current_dir_tmp,sizeof(target));

    // 移除结尾的斜杠（rmdir需要）
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }

    // 检查目录是否存在
    /* if (access(target, F_OK) != 0) { */
    /*     fprintf(stderr, "Directory does not exist: %s\n", target); */
    /*     return false; */
    /* } */
    char sql[5000] = {0};
    sprintf(sql,"select * from %s where user_name = '%s' and id = '%d' and is_delete = 0 and type = 'd';", 
            TABLE_NAME,css->user_name,css->current_dir_tmp_id);
    printf("rmsql1:%s\n",sql);
    mysql_store_result(css->mysql);
    int qret = mysql_query(css->mysql,sql);
    if(qret != 0){
        printf("rmdir-Error1: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }
    MYSQL_RES *rows =mysql_store_result(css->mysql);

    if(!mysql_num_rows(rows)){
        printf("the dir not exist\n");
        send(css->netfd,"the dir not exist",18,0);
        return -1;
    }

   //check empty or not
    char sql2[5000] = {0};
    sprintf(sql2,"select * from %s where user_name = '%s' and parent_id = '%d' and is_delete = 0;",
            TABLE_NAME,css->user_name,css->current_dir_tmp_id);
    printf("rmsql2:%s\n",sql2);
    mysql_store_result(css->mysql);
    int qret2 = mysql_query(css->mysql,sql2);
    if(qret2 != 0){
        printf("rmdir-Error2: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }
    MYSQL_RES *rows2 =mysql_store_result(css->mysql);
    if(mysql_num_rows(rows2)){
        printf("the dir not empty\n");
        send(css->netfd,"the dir not empty",18,0);
        return -1;
    }

    /* // 检查是否为目录 */
    /* struct stat path_stat; */
    /* if (stat(target, &path_stat) || !S_ISDIR(path_stat.st_mode)) { */
    /*     fprintf(stderr, "Not a directory: %s\n", target); */
    /*     return false; */
    /* } */

    // 删除空目录
    /* if (rmdir(target)) { */
    /*     perror("rmdir failed"); */
    /*     return false; */
    /* } */
    char sql3[5000] = {0};
    sprintf(sql3,"update %s set is_delete = 1 where user_name = '%s' and id = '%d' and is_delete = 0;",
            TABLE_NAME,css->user_name,css->current_dir_tmp_id);
    mysql_store_result(css->mysql);
    int qret3 = mysql_query(css->mysql,sql3);
    if(qret3 != 0){
        printf("rmdir-Error3: %s\n", mysql_error(css->mysql));
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }

    printf("remove success!\n");
    send(css->netfd,"rmsuccess",9,0);

    return 0;
}

int opt_dir(ClientSession *css,int opt,char *recv_path){                                 

    bzero(css->recv_path,sizeof(css->recv_path));
    strncpy(css->recv_path,recv_path,strlen(recv_path));

    if(opt == 1){
        cd_dir(css);
    }else if (opt == 2){
        ls_dir(css);
    }else if (opt == 3){
        pwd_dir(css);
    }else if (opt ==4){
        mk_dir(css);
    }else if(opt == 5){
        rm_dir(css);
    }else{
        printf("error option num!\n");
        send(css->netfd,"!Some Error...",15,0);
        return -1;
    }
    printf("finish topname:%s\n——————————————\n",css->pcn->name);

    return 0;
}

